//
//$Id: app_omp.cpp 695 2011-04-07 19:15:27Z andrew.tsyganov $
#include "stdafx.h"
#include "../src/refam/include/utils.h"
#include "../src/refam/include/fa.h"
#include "../src/refam/include/min_kw_omp.h"
#include "../src/refam/include/min_com_omp.h"
#include "../src/refam/include/re.h"
#include "../src/refam/include/app_omp.h"
#include "omp.h"

#if defined(_WIN32)
#include "include/dirent.h"
#else
#include <dirent.h>
#endif

using namespace std;
using namespace com;
using namespace kw;
using namespace app;

int App_OMP::run(int argc, char* argv[]) const
{
    string command = ToLower(argv[1]);

    if (command == "build_ba")      return build_ba(argc, argv);
    if (command == "build_com")     return build_com(argc, argv);
    if (command == "canonize")      return canonize(argc, argv);
    if (command == "codeterminize") return codeterminize(argc, argv);
    if (command == "determinize")   return determinize(argc, argv);
    if (command == "equivalent")    return equivalent(argc, argv);
    if (command == "export")        return export_(argc, argv);
    if (command == "generate")      return generate(argc, argv);
    if (command == "isomorphic")    return isomorphic(argc, argv);
    if (command == "min_com")       return min_com(argc, argv);
    if (command == "min_kw")        return min_kw(argc, argv);
    if (command == "re2fa")         return re2fa(argc, argv);
    if (command == "reverse")       return reverse(argc, argv);
    
    cout << "Unknown command!" << endl;
    return -1;
}

int App_OMP::build_ba(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: build_ba input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    vector<COM_Statistics> vcoms;

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                COM_Parameters cp;
                Min_COM_OMP mcom(fa, cp) ;
                mcom.construct_BA();
                FA const& ba = mcom.get_BA();
                ba.save_XML(CreatePath(dir2, name + "_ba." + ext));
                vcoms.push_back(mcom.stat_);
            }
        }
    }

    closedir(dp);

    cout << endl;
    ProcessCOMStatistics(cout, vcoms);
    cout << endl;

    return 0;
}

int App_OMP::build_com(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: build_com input_dir output_dir" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    vector<COM_Statistics> vcoms;

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                COM_Parameters cp;
                Min_COM_OMP mcom(fa, cp) ;
                mcom.construct_COM();
                FA const& com = mcom.get_COM();
                com.save_XML(CreatePath(dir2, name + "_com." + ext));
                vcoms.push_back(mcom.stat_);
            }
        }
    }

    closedir(dp);

    cout << endl;
    ProcessCOMStatistics(cout, vcoms);
    cout << endl;

    return 0;
}

int App_OMP::min_com(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: min_com input_dir output_dir [options.xml [seed]]" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    COM_Parameters comp;
    if (argc >= 5)
    {
        string file = argv[4];
        if (!comp.load_XML(file))
        {
            cout << "Error reading options file! Proceed with default options." << endl;		
        }
    }

    int seed = 0;
    if (argc >= 6)
    {
        seed = atoi(argv[5]);
    }

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    vector<COM_Statistics> vcoms;

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        //if (name != "les03") continue;

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                Min_COM_OMP mcom(fa, comp);
                mcom.minimize(seed);
                vcoms.push_back(mcom.stat_);
                
                for (u_t j = 0; j < mcom.stat_.u_[com::MIN_COUNT]; ++j)
                {
                    mcom.v_min_[j].save_XML(CreatePath(dir2, name + "_min_" + IntToStringZ(j, mcom.stat_.u_[com::MIN_COUNT]) + "." + ext));
                }

                if (comp.verbosity_ > 0)
                {
                    cout << endl;
                    PrintLine(cout, 90, '/');
                }
            }
        }
    }

    closedir(dp);

    cout << endl;
    ProcessCOMStatistics(cout, vcoms);
    cout << endl;

    return 0;
}

int App_OMP::min_kw(int argc, char* argv[]) const
{
    if (argc < 4)
    {
        cout << "Not enough parameters!" << endl;
        cout << "Command usage: min_kw input_dir output_dir [options.xml [seed]]" << endl;
        return 1;
    }

    string dir1 = argv[2];
    string dir2 = argv[3];

    KW_Parameters kwp;
    if (argc >= 5)
    {
        string file = argv[4];
        if (!kwp.load_XML(file))
        {
            cout << "Error reading options file! Proceed with default options." << endl;		
        }
    }

    int seed = 0;
    if (argc >= 6)
    {
        seed = atoi(argv[5]);
    }

    DIR *dp;
    struct dirent *dirp;
    if ((dp  = opendir(dir1.c_str())) == NULL) 
    {
        cout << "Error opening " << dir1 << endl;
        return 1;
    }

    vector<KW_Statistics> vkws;

    while ((dirp = readdir(dp)) != NULL) 
    {
        string fname(dirp->d_name);
        string file = CreatePath(dir1, fname);
        string dir, name, ext;

        SplitFileName(file, dir, name, ext);

        //if (name != "les004") continue;

        if (ext == "xml")
        {
            FA fa;

            if (GetFA(file, fa))
            {
                Min_KW_OMP mkw(fa, kwp);
                mkw.minimize(seed);
                vkws.push_back(mkw.stat_);
                
                for (u_t j = 0; j < mkw.stat_.u_[kw::MIN_COUNT]; ++j)
                {
                    mkw.v_min_[j].save_XML(CreatePath(dir2, name + "_min_" + IntToStringZ(j, mkw.stat_.u_[kw::MIN_COUNT]) + "." + ext));
                }

                if (kwp.verbosity_ > 0)
                {
                    cout << endl;
                    PrintLine(cout, 90, '/');
                }
            }
        }
    }

    closedir(dp);

    cout << endl;
    ProcessKWStatistics(cout, vkws);
    cout << endl;

    return 0;
}

void If_Debug_Press_Enter();

int main(int argc, char* argv[])
{
    App_OMP app;

    if (argc < 2)
    {
        cout << "Not enough parameters!" << endl;
        If_Debug_Press_Enter();
        return 1;
    }
    else
    {
        int r = app.run(argc, argv);
        If_Debug_Press_Enter();
        return r;
    }
} 




//-----------------------------------------------------------------------------------------------------------------//
void waterloo()
{
/*
    FA a("../automata_samples/waterloo.xml");
    //a.print_TXT(cout);

    COM_Parameters cp;
    Min_COM_OMP mcom(a, cp, 1);
    mcom.prepare();
    
    vector<Label> com_names(14);
    com_names[0]  = "13";
    com_names[1]  = "14";
    com_names[2]  = "10";
    com_names[3]  = "12";
    com_names[4]  = "4";
    com_names[5]  = "2";
    com_names[6]  = "8";
    com_names[7]  = "6";
    com_names[8]  = "11";
    com_names[9]  = "9";
    com_names[10] = "1";
    com_names[11] = "7";
    com_names[12] = "5";
    com_names[13] = "3";
    mcom.ca_.set_States(com_names);

    vector<Label> com_symbols(2);
    com_symbols[0] = "a";
    com_symbols[1] = "b";
    mcom.ca_.set_Symbols(com_symbols);
    
    mcom.ca_.swap_States(0, 10);
    mcom.ca_.swap_States(1, 5);
    mcom.ca_.swap_States(2, 13);
    mcom.ca_.swap_States(3, 4);
    mcom.ca_.swap_States(4, 12);
    mcom.ca_.swap_States(5, 7);
    mcom.ca_.swap_States(6, 11);
    mcom.ca_.swap_States(7, 11);
    mcom.ca_.swap_States(8, 9);
    mcom.ca_.swap_States(9, 13);
    mcom.ca_.swap_States(10, 13);
    mcom.ca_.swap_States(11, 12);
    mcom.ca_.swap_States(12, 13);
    mcom.ca_.print_TXT(cout);

    Label st;
*/
/*
    mcom.ca_.remove_State(mel.ca_.get_State_ID("2"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("4"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("7"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("9"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("11"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("13"));
    mcom.ca_.remove_State(mel.ca_.get_State_ID("14"));
    mcom.ca_.set_Name("SUBCOM(Waterloo)");
    mcom.ca_.print_TXT(cout);
*/
    //FA dcom;
    //vector<Subset> vs_com;
    //Determinize(mcom.ca_, dcom, vs_com);
    //Labels_Prefix lp_com("", "");
    //Labels_Prefix lp_dcom("s", "m");
    //dcom.print_TXT(cout, dcom, vs_com, lp_com, lp_dcom); 
    //cout << "equiv = " << AreEquivalentDFAs(mcom.drmda_, mcom.mdrmda_) << endl;
}



//EOF!
